﻿﻿/**
     * ********************************* Ccay IGrid Editor
     * **********************************
     */
(function(IGrid, Const) {
    /** 扩展IGrid的manager管理器 */
    Ccay.UI.XControl.extendIManager("XGrid", {
                /**
                 * @description 获取编辑面板
                 * @return {JQDom}
                 */
                getEditPanel : function() {
                    return DomClass.getProp(this, this.getBodyPanel(), "pedit", ".ccay-igrid-editpanel", true);
                },
                /**
                 * @description 获取活动的编辑器，若存在，则返回；不存在，则返回null
                 * @return {JQDom}
                 */
                getActiveEditor : function() {
                    return $.isEmptyObject(this.op._activeEditor) ? null : this.op._activeEditor;
                },
                /**
                 * @description 清除所有活动的编辑器
                 */
                clearActiveEditor : function() {
                    var activeEditors = this.op._activeEditor;
                    if (activeEditors) {
                        // 遍历编辑器并清除
                        $.each(activeEditors, function(i, editCell) {
                                    // 取消编辑
                                    GridEditor.cancelEdit(editCell);
                                });
                        this.op._activeEditor = {};
                        this.op._activeEditTr = this.op._activeTd = null;
                    }
                },
                /**
                 * @description 结束编辑
                 */
                endEdit:function(){
                	var grid = this, activeEditor = grid.getActiveEditor() || [];
					$.each(activeEditor,function(i,editor){
						GridEditor.endEdit(editor,grid,grid.op);
					});
					grid.clearActiveEditor();
                },
                /**
                 * @description 获取更新的数据
                 * @return {Array}
                 */
                getUpdatedRecords : function() {
                    return this.op.Storage.getUpdatedRecords();
                },
                // 获取所有变化的数据（inserted,updated,deleted）
                getRecords : function() {
                    var re = this.op.Storage.getChangedRecords();
                    if (re.insertedRecords.length || re.updatedRecords.length || re.deletedRecords.length) {
                        return re;
                    } else {
                        return null;
                    }
                },
                // 获取所有未变化的数据（非inserted,非updated,非deleted）
                getUnvariedRecords : function() {
                    var re = this.op.Storage.filter(function(item, index) {
                                if (!(this.isNew(item) || this.isUpdated(item) || this.isDeleted(item))) {
                                    return item;
                                }
                            });
                    return re;
                },
                // 获取当前igrid中所有的数据
                getAllRecords : function(fields, fnFilter, copy, fnHandle, includeInserted) {
                    // 判断是否是bool类型，若是，则给includeInserted赋值
                    if (typeof(fields) == "boolean") {
                        includeInserted = fields;
                        fields = null;
                    }
                    return this.op.Storage.filter(fields, fnFilter, copy, fnHandle, includeInserted);
                },
                // 获取所有变化的数据（inserted,updated,deleted），并且验证，如果数据不通过验证，则返回false，否则返回数据集。
                getValidRecords : function (allowEmpty) {
                    return this.valid(allowEmpty);
                },
                validRecords : function (records, allowEmpty) {
                    var grid = this;
                    if (records && records.length) {
                        // 创建验证器
                        var validator = grid.getEditPanel().children().data("validator"), isError;
                        // 遍历数据
                        $.each(records, function (rIdx, record) {
                            // 验证单个数据对象
                            if (!grid.validRecord(record, validator)) {
                                isError = true;
                                return false;
                            }
                        });
                        return isError ? false : true;
                    }
                    return (allowEmpty != null) ? allowEmpty : true;
                },
                validRecord: function (record, validator) {
                    !validator && (validator = this.getEditPanel().children().data("validator"));
                    // 验证单个数据对象
                    var errorMsg = validator.valid(record),
                        grid = this, op = grid.op, td,
                        pageInf = op.pagerOp && op.pagerOp.pageInf;
                    if (errorMsg !== true) {
                        // 设置错误数据标示
//                      record._errorNo = $.newGuid();
                        if (record._cachePos != null && !record._newIndex) {
                            dataIndex = (record._cachePos == 0) ? (record._index + 1) : (record._cachePos + 1);
                            if (pageInf && (dataIndex <= pageInf.startIndex || dataIndex > pageInf.endIndex)) {
                                return false;
                            }
                        }
                        for (var errorField in errorMsg) {
                            td = grid.getCellByField(record.rowIdx, errorField);
                            td.length && GridEditor.callDataEditor(grid, grid.getColumnOp(td), record, record.rowIdx);
                        }
                        return false;
                    }
                    return true;
                },
                /**设置前台校验错误信息
                 * @return Boolean
                 * 
                 */
                setErrorMsg: function (records) {
                    var grid = this;
                    if (records && records.length) {
                        // 创建验证器
                        var errorRecords = {},
                            errorNo,
                            validator = Ccay.Validator.create({fields:grid.op.validOp.rule});
                        // 遍历数据
                        $.each(records, function (rIdx, record) {
                            var errorMsg = validator.valid(record);
                            if (errorMsg != true){
                                // length单条记录错误列数
                                var length = 0;
                                for(var i in errorMsg){
                                    length ++;
                                };
                                errorMsg.lenght = length;
                                // 添加错误标识,并添加到错误数据集中
                                errorNo = $.newGuid();
                                record._errorNo = errorNo;
                                errorRecords[errorNo] = errorMsg;
                            }
                        });
                        // 错误数据集不为空时设置
                        if(!$.isEmptyObject(errorRecords)){
                            grid.op._errorMsg = errorRecords;
                            return true;
                        }
                        return false;
                    }
                    return false;
                },
                validEditor: function (isValid) {
                    var grid = this, result = true, activeEditors = grid.getActiveEditor();
                    if (activeEditors) {
                        // 遍历所有的动态编辑器，并关闭
                        $.each(activeEditors, function(i, editCell) {
                            var editor = editCell.children(".grid-editor"),
                                td = editor.data("caller");
                                    if (!grid.getColumnOp(td).editor.valid(editor)) {
                                        isValid && editor.focus();
                                        result = false;
                                        return;
                                    }
                                })
                    }
                    return result;
                },
                /**
                 * @description 验证
                 * @return {Boolean}
                 */
                valid : function(allowEmpty) {
                    // 验证编辑器
                    if (GridEditor.check(this, true)) {
                    	var op = this.op;
                        // 执行行编辑结束事件
                        op._endEditTriggerTr && GridEditor.endRowEdit(this, op);
                        // 验证数据
                        var result = GridEditor.checkData(this, allowEmpty);
                        if(!result){
	                        var grid = this;
	                        $.each(grid.getActiveEditor(),function(i, editCell){
	                        	 // 定位错误
	                            var cellLeft = editCell[0].offsetLeft + editCell.width(), cellTop = editCell[0].offsetTop, body = grid.getBodyPanel(), width = body.width(), scrollTop = body.scrollTop(), height = body.height() + scrollTop, left = cellLeft - width, top = cellTop < scrollTop || cellTop > height;
	                            // 同步滚动
	                            if (left > 0 || top) {
	                                grid.syncScroll(left > 0 ? left : null, top ? cellTop : null);
	                            }
	                        	var editTd = editCell.children(".grid-editor").data("caller");
	                        	editTd && grid.scrollTo(grid.getColumnOp(editTd));
	                        	return false;
	                        });
                        }
                        return result;
                    }
                    return false;
                },
                /**
                 * @description 请求编辑器
                 * @param td {JQDom} 单元格对象
                 */
                callEditor : function (td) {
                    var isCallEditor = GridEditor.callEditor(null, td, this);
                    // 标示光标定位行
                    (isCallEditor !== false) && this.setFocusRow(this.getCellRow(td));
                    // 请求编辑器
                    return isCallEditor;
                },
                /**
                 * @description 请求编辑器
                 * @param tr {JQDom} 行对象
                 */
                triggerRowEditor: function (tr, col) {
                    // 标示光标定位行
                    this.setFocusRow(tr);
                    // 请求编辑器
                    GridEditor.triggerRowEditor(tr, this, col);
                },
                /** @description 更新单元格数据并验证
				 * 	@param {jDom} cell 单元格对象
				 */
				updateCellData: function (cell, value, oldValue) {
					var cellOp = this.getColumnOp(cell), validMsg;
					// 设置当前单元格的值
					if (cellOp.editable !== false && !GridEditor.compareValue(value, oldValue) && this.cellValue(cell, cellOp, value, true) !== false) {
						validMsg = cellOp.rule ? Ccay.Validator.valid(value, cellOp.rule) : true;
						if (validMsg == true) {
							!this.isNewRow(cell.parents("tr:first")) && cell.addClass('cell-update');
						} else {
							cell.addClass("grid-tip igrid-servervalid-error").attr("tip", validMsg);
							this.op.showStatus && GridEditor.updateErrorMsg(this, this.getRowData(cell), this.getValueField(cellOp.field), validMsg);
						}
					}
				}
            });

    var GridEditor = IGrid.Editor = {
        /** @description 设置列的编辑器配置
         *  @param {Object} grid IGrid对象
         *  @param {Object} col 列的配置信息
         *  @param {JsonObject/Array/String} field 属性值
         *  @return {IGrid}
         */
        setCol : function(grid, col, op) {
            // 过滤：内置列、列类型、不能编辑列
            if (!col.inner && !col.columnType && col.editable !== false) {
                // 列的编辑属性赋值
                col.editorOp = $.extend({
                    type: col.type,
                    field : col.valueField || col.field,
                    format: col.format,
                    rule: col.rule
                }, col.editorOp);
                if (!col.editor || typeof(col.editor) == "string") {
                    // 通过type类型创建编辑器
                    col.editor = Ccay.Editor.get(col.editor || col.editorOp.type);
                }
                // 是否显示编辑图标
                if (op.editMode != "insert") {
                	op.showColumnIcon && (col._headCss += " editor");
                	op.customTable && (col.cssName += " editor");
                }
                // 设置列的点击编辑事件，若是新增编辑模式的数据则新增可编辑，其他不可编辑；其他编辑模式全部可编辑
                col.eNo = (grid.op.editMode == "insert") ? ("<% if (data._inserted) { %>" + "edit" + "<% } else { %>" + 'noedit' + "<% } %>") : 'edit';
                // 配置编辑表单的字段属性
                var newCol = $.extend({},col);
                newCol.field = newCol.valueField || newCol.field;
                op.modalOp.fields.push(newCol);
                // 设置列的验证配置
                GridEditor.setValid(op, col);
            }
        },
        /**
         * @description 设置列的验证配置
         * @param {Object}
         *            op IGrid的配置参数
         * @param {Object}
         *            col 列的配置信息
         */
        setValid : function(op, col) {
            // 验证属性设置
            if (col.valid !== false && col.editorOp.rule) {
                op.validOp.rule[col.valueField || col.field] = col.editorOp.rule;
                // 设置必填标示
                if (col.editorOp.rule.required) {
                	op.customTable ? (col.attr._required = "required") : (col.headHtml += "<font color='red'>&nbsp;*</font>");
                }
            }
        },
        /** @description 生成编辑form
         *  @param {Object} grid IGrid对象
         *  @return {JQDom}
         */
        buildPanel : function(grid, op) {
            if(!op.modal){
                op.modal = Ccay.Modal.create(op.modalOp);
            }
            var form = $.create("div").appendTo(grid.getBodyPanel()).xForm({
                        showHead : false,
                        tagName :"div",
                        innerButton : false,
                        renderType : "edit",
                        modal : op.modal,
                        layout :"gridedit",
                        buildControlTag : false
                    }).dom.addClass("ccay-igrid-editpanel").bind("click focusin", function(e) {
                        // 点击或光标进入，则标识正在编辑
                        op._inEdit = true;
                    }).focusout(function(e) {
                    	// 当光标定位在横向滚动条时，不执行编辑结束
                    	if (!$(e.relatedTarget).hasClass("igrid-scroller") || !op.rowEdit) {
	                        // 光标移除出，则清除正在编辑标识
	                        op._inEdit = null;
	                        // 若编辑结束的方法存在，则清除
	                        op._editClose && clearTimeout(grid.op._editClose);
	                        // 重新创建编辑结束的方法
	                        op._editClose = setTimeout(function() {
                                // 正在编辑的标识不存在，则验证编辑器
                                op._inEdit || GridEditor.check(grid);
                                // 清除编辑结束的方法
                                delete op._editClose;
                            }, 200);
                    	}
                    }).keydown(function(e) {
                        // 编辑器的键盘事件
                        return GridEditor.keydown(grid, e);
                    }).submit(function(e) {
                        return false;
                    });

            for (var col, i = 0; col = op.columns[i]; i++) {
                if (!col.inner && !col.columnType && col.editable !== false) {
                    col._editCtr = form.find("[name='" +( col.valueField || col.field) + "']").attr('eno', 'edit').addClass("grid-editor").removeClass("ccay-control");
                    col._editCtr.parent().attr('_col', col._i);
                }
            }
        },
        /**
         * @description 相应键盘事件，可通过tab/Shift + tab 支持编辑单元格的跳转
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            e 事件对象
         * @return {Boolean}
         */
        keydown : function(grid, e) {
            // 判断是否按键是否是TAB键
            if (e.keyCode == 9) {
                var ctr = $.getEventTarget(e), td = ctr.data('caller'), all = grid.getEditPanel().find(".grid-editor"), actives = all.filter(":visible");
                /**
                 * 判断当前编辑器是否是已经激活的，最后一个（如果按住了Shift 则判断是否是最前一个），
                 * 如果是边缘，则不处理，直接采用浏览器的默认快捷键处理机制，切换到下一个编辑器编辑， 否则进入igrid
                 * 编辑器快捷键处理逻辑中
                 */
                if (ctr[0] == actives[e.shiftKey ? 0 : actives.length - 1]) {
                    // 切换编辑列前，需要先验证当前正编辑的单元格，如果验证不通过，则不能切换
                	ctr.data("ctr_locked", false);
                    if (GridEditor.check(grid)) {
                        /**
                         * 得到当前列序号，拿到列设置信息，根据是否按下 shirt 键，寻找下一个或上一个可编辑列
                         * 找到可编辑列后，通过调用scrollTo 滚动到定位到该列，并判断该列是否是可编辑并且可见，再激活编辑器
                         * 激活编辑器失败则继续在循环中寻找下一个编辑器，直到正确激活编辑器或推退出循环
                         */
                        var nextTd, columns = grid.getOrderColumns(), colIndex = td.attr("_col") * 1, go = e.shiftKey ? -1 : 1;
                        // 遍历columns 并拿到当前编辑列的实际显示索引
                        for (var i = 0, col; col = columns[i]; i++) {
                            if (col._i == colIndex) {
                                colIndex = i;
                                break;
                            }
                        }
                        for (var i = colIndex + go, col; col = columns[i]; i += go) {
                            // 若该列是不可编辑的，则继续循环，若是可编辑的，则滚动到该列所在的位置
                            if (col.editable !== false) {
                                nextTd = grid.scrollTo(col);
                                // 修复在chrome下 firefox下 TAB键后 form的focusin 与
                                // focusout 顺序混乱出现的bug
                                $("a:first").focus();
                                if (nextTd.is("[eno='edit']:visible") && GridEditor.showEditor(nextTd, grid) !== false) {
                                    return false;
                                }
                            }
                        }
                        // 如果继续往下执行，说明在当前行没有找到可编辑的列，需要进行换行编辑
                        var currTr = td.parents("tr:first"), rowIndex = currTr.attr("_row") * 1;
                        colIndex = e.shiftKey ? columns.length - 1 : 0;
                        // 设置光标定位行
                        var nextRow = e.shiftKey ? currTr.prevAll("tr.grid-row:first") : currTr.nextAll("tr.grid-row:first");
                        if(nextRow.length == 0){
                            return true;
                        }
                        grid.setFocusRow(nextRow);
                        // 去除上一行的光标定位标示
                        currTr.removeData("focusin");
                        // 切换行后，执行激活编辑器算法，直到正确激活编辑器或推退出循环
                        for (var i = colIndex; col = columns[i]; i += go) {
                            if (col.editable !== false) {
                                nextTd = grid.scrollTo(col);
                                // 修复在chrome下 firefox下 TAB键后 form的focusin 与
                                // focusout 顺序混乱出现的bug
                                $("a:first").focus();
                                if (nextTd.is("[eno='edit']:visible") && GridEditor.showEditor(nextTd, grid) !== false) {
                                    return false;
                                }
                            }
                        }
                    } else {
                        // 验证不通过，则 阻止浏览器默认事件
                        return false;
                    }
                } else {
                    // 得到当前编辑器在actives的索引值
                    for (var i = 0; i < actives.length; i++) {
                        if (actives[i] == ctr[0]) {
                            break;
                        }
                    }
                    // 通过当前索引值，与按键得到下一个目标编辑器的_col
                    var _colIndex = $(e.shiftKey ? actives[i - 1] : actives[i + 1]).parent().attr("_col");
                    if(_colIndex){
	                    setTimeout(function() {
	                          grid.scrollTo(grid.op.columns[_colIndex]);
	                     }, 0)
                    }
                }
                // 判断是否按键是否是ESC键，若是，则取消编辑
            } else if (e.keyCode == 27) {
                if (grid.op.usingEsc !== false) {
                    var ctr = $(e.target);
                    if (!ctr.hasClass("grid-editor")) {
                        return false;
                    } else {
	                    var oldVal = ctr.data('old-val'), 
	                        activeEditors = grid.getEditPanel().find(".grid-editor:visible"),
	                        col = grid.getColumnOp(ctr.data('caller'));
	                    // 若原始值是对象，则显示对象的value属性值，否则，直接显示原始值
		                if ($.isPlainObject(oldVal) && Ccay.DataHelper.isEmpty(oldVal.value)) {
		                      return false;
		                } else if (Ccay.DataHelper.isEmpty(oldVal)) {
		                	 return false;
		                }
	                    // 如果同时存在多个编辑器，则不退出编辑，否则，验证该编辑器
	                    if (activeEditors.length == 1) {
	                    	var bodyPanel = grid.getBodyPanel();
			            	// 还原grid的高度
			            	if (bodyPanel.data("isFixed")) {
			                	bodyPanel.css("min-height", grid.op.minHeight || "");
			                	bodyPanel.data("isFixed", null);
			                }
	                        GridEditor.cancelEdit(ctr.parent(), grid.op);
	                        oldVal = "";
	                    }
	                    col.editor.setValue(ctr, oldVal);
                    }
                }
                return false;
            }
            return true;
        },
        /**
         * @description 请求编辑器
         * @param {Object}
         *            e 事件对象
         * @param {Object}
         *            td 列对象
         * @param {Object}
         *            grid IGrid对象
         */
        callEditor : function(e, td, grid) {
            // 判断是否是已经是编辑列和是否删除行，并且隐藏的话，就不执行编辑操作
            if (td.isVisiable() && !td.hasClass('grid-editor') && (!grid.getCellRow(td).hasClass(Const.deleted.css) || td.attr('rowspan') * 1 > 1)) {
                // 判断之前的活动编辑器
                if (GridEditor.check(grid) !== false && td.parent().length > 0) {
                    // 标识正在编辑
                    grid.op._inEdit = true;
                    // 清空活动的编辑器
                    grid.op._activeEditor = {};
                    // 显示编辑器
                    return GridEditor.showEditor(td, grid);
                }
            }
            return false;
        },
        /**
         * @description 显示编辑器 如果返回值为false 则编辑器开启失败
         * @param {Object}
         *            td 列对象
         * @param {Object}
         *            grid IGrid对象
         * @param {Boolean}
         *            isTrigger 是否是连锁编辑
         * @param {Object}
         *            col 列的配置信息
         */
        showEditor : function(td, grid, isTrigger, col) {
            // 获取行对象
            var op = grid.op, tr = grid.getCellRow(td), rowData = grid.getRowData(tr);
            // 获取列设置
            col || (col = grid.getColumnOp(td));
            // 若当前单元格存在自定义验证错误，则清除
            if (td.hasClass("igrid-servervalid-error")) {
            	td.removeClass("igrid-servervalid-error grid-tip").removeAttr("tip");
            	GridEditor.updateErrorMsg(grid, rowData, grid.getValueField(col.field), null, true);
            }
            // 判断光标是否还在同一行，若不在，则执行行编辑前委托事件
            if (!tr.data("focusin")) {
                // 标示光标定位行
                tr.data("focusin", true);
                if (op.fnBeforeRowEdit) {
                    if (op.fnBeforeRowEdit.call(grid, rowData, tr) === false) {
                        return false;
                    }
                }
            }
            // 执行编辑之前委托事件
            if (op.fnBeforeEdit) {
                // 获取单元格中的数据
                var value = grid.cellValue(td, col);
                // 若返回false，则不显示编辑器
                if (op.fnBeforeEdit.call(grid, value, td, col, rowData) === false)
                    return false;
            }
            // 执行行编辑模式
            if (op.rowEdit) {
                GridEditor.triggerRowEditor(tr, grid, col);
                return;
            }
            // 显示编辑器，内置方法
            this._showEditor(td, grid, col, tr);
        },
        /**
         * @description 显示编辑器，内置方法
         * @param {Object}
         *            td 列对象
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            col 列的配置信息
         * @param {Object}
         *            tr 行对象
         * @param {Boolean}
         *            isTrigger 是否是连锁编辑
         */
        _showEditor : function(td, grid, col, tr, isTrigger) {
            col || (col = grid.getColumnOp(td));
            // 是否是触发对象，显示关联触发编辑器
            if (!isTrigger && col.editorOp && col.editorOp.trigger) {
                this.showTrigger(col.editorOp.trigger, tr, grid);
            }
            // 设置编辑器
            this.setEditor(grid, td, col, isTrigger);
            // 显示触发之后的关联对象
            if (!isTrigger && col.editorOp && col.editorOp.afterTrigger) {
                this.showTrigger(col.editorOp.afterTrigger, tr, grid);
            }
        },
        /**
         * @description 触发行编辑模式
         * @param {Object}
         *            tr 行对象
         * @param {Object}
         *            grid IGrid对象
         * @param {triggerCol}
         *            triggerCol 联动的列设置
         */
        triggerRowEditor : function(tr, grid, triggerCol) {
            var op = grid.op;
            op.rowEdit = true;
            // 遍历所有可编辑的单元格
            tr.find("[eno='edit']").each(function() {
                var td = $(this), col = grid.getColumnOp(td);
                // 设置编辑器
                if (!op.fnCheckRowEditor || op.fnCheckRowEditor.call(grid, td, tr, col, triggerCol) !== false) {
                    Ccay.UI.setCtrHandler(col._editCtr, "fnLocked", function(params){
                        if (this.data("ctr_locked") === false)
                            this.removeData("ctr_locked");
                        op._rowLocked = params;
                    });
                    GridEditor.setEditor(grid, td, col, triggerCol._i !== col._i);
                }
            });
        },
        /**
         * @description 设置编辑器
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            td 列对象
         * @param {Object}
         *            col 列的配置信息
         * @param {Boolean}
         *            isTrigger 是否是连锁编辑
         */
        setEditor : function(grid, td, col, isTrigger) {
            if (col.editor) {
                // 获取单元格的值
                var value = grid.cellValue(td, col), ctr = col._editCtr;
                //lwx200947 修复人员联想框编辑器由于id 全相同，导致所有的title 都是最后一个的问题
                if(col.editor.type == "ldap"){
                	ctr.attr("title",value.text);
                }
                $.type(value) == "date" && ( value = value.getUTCTime());
                // 缓存值以及单元格对象
                col._editCtr.data('old-val', value).data('caller', td);
                // 给编辑器设置值
                col.editor.setValue(ctr, value);
                // 设置样式
                GridEditor.setStyle(grid, ctr, td, col, isTrigger);
                // 若没有联动编辑，则将光标定位在该编辑器中
                if (!isTrigger) {
                    grid.op._activeTd = td;
                    var tagName = ctr[0].tagName;
                    if (tagName == "TEXTAREA" || (tagName == "INPUT" && ctr.attr("type") == "text"))
                        ctr.select();
                    ctr.focus();
                    // 修复chrome浏览器光标失去问题
                    setTimeout(function(){ctr.focus();},10)
                }
            }
        },
        /**
         * @description 显示触发编辑器
         * @param {Object}
         *            triggers 联动列配置集合
         * @param {Object}
         *            tr 行对象
         * @param {Object}
         *            grid IGrid对象
         */
        showTrigger : function(triggers, tr, grid) {
            $.each(triggers, function(i, field) {
                        var triggerCell = tr.find("[field='" + field + "']");
                        // 显示联动的编辑器
                        triggerCell.length && GridEditor._showEditor(triggerCell, grid, null, tr, 1);
                    })
        },
        /**
         * @description 设置编辑器样式
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            ctr 编辑器对象
         * @param {Object}
         *            td 列对象
         * @param {Object}
         *            col 列的配置信息
         */
        setStyle : function(grid, ctr, td, col, isTrigger) {

            var editCell = ctr.parent(), op = grid.op;
            ctr.manager().hide(true);
            this.fixPosition(grid, ctr, td, editCell, col, isTrigger);
            // 将编辑器进行缓存
            op._activeEditor[editCell.attr('_col')] = editCell;
            // 记录编辑行
            op._activeEditTr = grid.getRowIndex(td.parent());
        },
        activeEditor: function (grid, col) {
            var activeEditors = grid.getActiveEditor(),
                bodyPanel = grid.getBodyPanel();
            if (activeEditors) {
                $.each(activeEditors, function(i, editCell) {
                    var pos = editCell.children(".grid-editor").data('caller').position();
                    editCell.css({
                        left : pos.left + 1,
                        top : pos.top + 1 + bodyPanel.scrollTop()
                    });
                });
            }
        },
        fixPosition : function(grid, ctr, td, editCell, col, isTrigger) {
            var pos = td.position(), ctrPos = {
                left : pos.left + 1,
                top : pos.top + 1
            }, scrollTop = grid.getBodyPanel().scrollTop(), width = td.outerWidth() - 2, height = td.outerHeight() + 1, isFix, tagName = ctr[0].tagName;
            // 修正高度
            editCell.outerHeight() < height && editCell.height(height - 3);
            col || (col = grid.getColumnOp(td));
            // 若单元格被隐藏，则显示
            if (width < 5) {
                if (isTrigger)
                    return;
                grid.scrollTo(col);
                width = td.outerWidth();
            }
            if (col.fnFixEditor) {
                col.fnFixEditor(grid, ctr, td, editCell, col, ctrPos);
            } else {
                // 判断是否是标准的输入对象
                if (ctr.attr('type') == 'text' || tagName == 'SELECT' || tagName == "TEXTAREA") {
                    ctr.width(width - 2);
                    // 是否进行修正
                    isFix = 1;
                } else {
                    width -= 1;
                    ctrPos.left += 1;
                    // 非标准模式下的计算高宽度以及编辑器所在的位置
                    if (!grid.op.customTable) {
                    	ctr.width("").css("margin-left", 0);
                        var ctrWidth = ctr.outerWidth(true), ctrHeight = ctr.outerHeight(true);
                        if (ctrWidth > width) {
                            ctr.width(width);
                        } else {
                            ctr.css("margin-left", (width - ctrWidth) / 2);
                        }
                    }
                }
                ctrPos.top += scrollTop;
            }
            //修复百分比模式下最后一列编辑器错位
            var isShow =false;
            if(grid.getBodyPanel().width() ==grid.getBodyPlace().width()){
            	isShow = true;
            }
            editCell.css(ctrPos).show();
            
            if(isShow && grid.getBodyPanel().width() !=grid.getBodyPlace().width()){
            	ctrPos.left -=(grid.getBodyPanel().width()- grid.getBodyPlace().width()-2);
            	editCell.css(ctrPos).show();
            }
            // 修正位置
            if (isFix) {
                var fix = editCell.attr("fix");
                if (fix == null) {
                    // 计算多种子元素的宽度
                    fix = ctr.innerWidth() - ctr.width();
                    if (fix <= 2) {
                    	// 表格宽度不够时，会被换行，导致计算不准确
                    	ctr.width(0);
                        var ctrSiblings = ctr.parent().children();
                        if (ctrSiblings.length != 1) {
                        	var firstCtrLeft = ctrSiblings.first().position().left,
                        		lastCrt = ctrSiblings.last(),
                        		lastCtrRigth = lastCrt.position().left + lastCrt.outerWidth();
                        	fix = lastCtrRigth - firstCtrLeft - ctr.innerWidth() + 7;
                        }
                    }
                    editCell.attr("fix", fix);
                }
                var editOp = col.editorOp;
                if(editOp && editOp.conf && editOp.conf.multi && editOp.conf.showType == "textarea"){
                	ctr.width(width - 5);
                }else ctr.width(width - 2 - fix * 1);
            }
            editCell.width(width);
            // 记录横向这对td的修正值
            ctr.data("fixedX", ctrPos.left - pos.left);
        },
        /**
         * @description 编辑结束
         * @param {Object}
         *            editCell 编辑器对象
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            op grid参数配置
         * @return {Boolean}
         */
        endEdit : function(editCell, grid, op) {
            var result = true, 
                ctr = editCell.children(".grid-editor");
            // 若编辑器是锁住状态，则结束编辑
            if (ctr.data("ctr_locked") || op._rowLocked)
                return result;
            // 获取单元格对象
            var td = ctr.data('caller');
            if (td) {
                var col = grid.getColumnOp(td),
                    tr = grid.getCellRow(td);
                // 验证编辑器
                if (col.editor.valid(ctr)) {
                    // 获取编辑器的值
                    var value = col.editor.getValue(ctr, true);
                    // 进行值比较
                    if (!this.compareValue(value, ctr, col)) {
                        if (grid.cellValue(td, col, value, true, ctr.data('old-val')) !== false) {
                            if (!grid.isNewRow(tr)) {
                            	td.addClass('cell-update');
                            	tr.hasClass(Const.updated.css) || tr.addClass(Const.updated.css);
                            }
                            // 只要有一个单元格编辑，就要执行行结束编辑
                            op._isChangeValue = true;
                        }
                    }
                    ctr.removeData('old-val').removeData('caller');
                    // 在单元格编辑状态结束中，捕获igrid行焦点切换，判断当前行与上一个焦点行是否为同一个，如果不是则触发上一个焦点行的行结束编辑事件fnEndRowEdit
                    if (op.fnEndRowEdit && op._isChangeValue && !op._endEditTriggerTr) {
                        // 缓存当前编辑行
                        op._endEditTriggerTr = tr;
                        op._endEditTriggerTrTime = setTimeout(function() {
                            GridEditor.endRowEdit(grid, op);
                        }, 500);
                    }
                    // 编辑完成后，修正错误数据
                    op.showStatus && grid.updateStatus("error");
                } else {
                	if(op.weakValid===true){
                		var weakPanel = $("#"+grid.id+"_weakPanel");
                		!weakPanel.length && (weakPanel=$('<div id="'+grid.id+'_weakPanel"></div>').appendTo(grid.getBodyPanel()));
                		var weakLabel = editCell.find("label");
                		var weakPos = editCell.position();
                		weakPos.top += grid.getBodyPanel().scrollTop();
                		var weakValid = $("<div style='position:absolute;'></div>").css(weakPos).width(editCell.width()).append(weakLabel).appendTo(weakPanel);
                		weakLabel.position().top>0 && weakLabel.css("top",td.outerHeight());
                    	ctr.removeClass("error error-ctr");
                    	setTimeout(function(){
                    		weakValid.remove();
                    		grid.getBodyPanel().css("min-height", op.minHeight || "");
                        },3000);
                	}else{
                		result = false;	
                	}
                    // 定位错误
                    var cellLeft = editCell[0].offsetLeft + editCell.width(), cellTop = editCell[0].offsetTop, body = grid.getBodyPanel(), width = body.width(), scrollTop = body.scrollTop(), height = body.height() + scrollTop, left = cellLeft - width, top = cellTop < scrollTop || cellTop > height;
                    // 同步滚动
                    if (left > 0 || top) {
                        grid.syncScroll(left > 0 ? left : null, top ? cellTop : null);
                    }
                    //ctr.focus();
                }
            }
            // 隐藏编辑器，清除缓存中的动态编辑
            if (result) {
            	var bodyPanel = grid.getBodyPanel();
            	
            	//修复igrid不设置高度时，且设置弱校验时，只有一行时错误信息高度不够显示不全。
				var bodyMinHeight = bodyPanel.css("min-height");
				
            	// 还原grid的高度
            	if (bodyPanel.data("isFixed")) {
                	bodyPanel.css("min-height", op.minHeight || "");
                	bodyPanel.data("isFixed", null);
                }
            	
            	//修复igrid不设置高度时，且行编辑校验失败时，只有一行时错误信息高度不够显示不全。
            	if(op.weakValid===true || 0 < grid.getEditPanel().find("div:visible label.error").length){
            		bodyPanel.css("min-height", bodyMinHeight || "");
            	}
                ctr.manager().hide();
                editCell.hide().css("height", "");
                delete op._activeEditor[editCell.attr('_col')];
                op._activeTd = null;
                $.isEmptyObject(op._activeEditor) && (op._activeEditTr = null);
                // 修正百分比模式下，滚动条的占位
               op.percentWidth && IGrid.Factory.fixScroll(grid, op);
            }
            return result;
        },
        /**
         * @description 行编辑结束
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            op grid参数配置
         * @return {Boolean}
         */
        endRowEdit: function (grid, op) {
            // 获取当前鼠标所在的焦点行
            var focusRow = grid.getFocusRow(), prevTr = op._endEditTriggerTr;
            // 判断当前行与上一个焦点行是否为同一个，并且是否还是编辑状态
            if (!focusRow.length || grid.getRowIndex(focusRow) != grid.getRowIndex(prevTr) || !op._inEdit) {
                // 获取行数据
                var rowData = grid.getRowData(prevTr);
                // 行编辑结束委托事件，返回true时，进行整行数据渲染
                if (op.fnEndRowEdit.call(grid, rowData, prevTr) == true) {
                    grid.renderRow(prevTr, rowData);
                }
                // 清除
                prevTr.removeData("focusin");
                op._isChangeValue = null;
            }
            // 清除
            clearTimeout(op._endEditTriggerTrTime);
            op._endEditTriggerTr = op._endEditTriggerTrTime = null;
        },
        /**
         * @description 取消编辑
         * @param {Object}
         *            editCell 编辑器对象
         */
        cancelEdit : function(editCell, op) {
            var ctr = editCell.css("height", "").hide().children('.grid-editor.error');
            ctr.removeClass('error').next('.error').remove();
            if (op) {
                op._activeEditor = {};
                op._activeEditTr = op._activeTd = null;
            }
        },
        /**
         * @description 比较值
         * @param {Object}
         *            value 编辑器的值
         * @param {Object}
         *            ctr 编辑器对象
         * @param {Object}
         *            col 列的配置信息
         * @param {Object}
         *            grid IGrid对象
         * @return {Boolean}
         */
        compareValue : function(value, ctr, col, grid,oldValue) {
            !oldValue && ( oldValue = ctr && ctr.jquery ? ctr.data('old-val') : ctr );
            // 字面量对象
            if ($.isPlainObject(value)) {
                return value.value == oldValue.value;
            } else {
                var type = $.type(value);
                // 日期对象
                if (type == 'date') {
                    return value - oldValue == 0;
                }
                return  Ccay.DataHelper.isEmpty(oldValue) === Ccay.DataHelper.isEmpty(value) && value == oldValue;
            }
        },
        /**
         * @description 验证grid的编辑器
         * @param {Object}
         *            grid IGrid对象
         * @return {Boolean}
         */
        check : function(grid, isValid) {
            // 获取动态编辑器
            var result = true, activeEditors = grid.getActiveEditor();
            if (activeEditors) {
                // 遍历所有的动态编辑器，并关闭
                $.each(activeEditors, function(i, editCell) {
                            if (!GridEditor.endEdit(editCell, grid, grid.op)) {
                                isValid && editCell.focus();
                                result = false;
                                return;
                            }
                        })
            }
            return result;
        },
        /**
         * @description 初始化验证
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            op grid参数配置
         */
        initValid : function(grid, op) {
            // 验证编辑面板
            var validator = grid.getEditPanel().children().data("validator");
            validator && (validator.errorPlacement =  function(error, ctr) {
                GridEditor.showError(grid, error, ctr);
            });
        },
        /**
         * @description 显示错误信息
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            error 错误标签对象
         * @param {Object}
         *            ctr 编辑器对象
         */
        showError : function(grid, error, ctr) {
            var td = ctr.data("caller");
            if (td) {
                // 设置错误提示信息：单元格有数据，则提示按ESC可退出编辑；否则，不提示
               // error.text(error.text() + (td.text().trim() && (grid.op.usingEsc !== false) ? $i18n("ccay.common.igrid.pressESC") : ""));
                error.text(error.text());
                // 设置错误标签的宽度
                error.width(ctr.width() - 10).addClass('error');
                ctr.addClass('error').after(error);
                // top相对bodyPanel的高度
				var top = ctr.parent().position().top, 
					height = ctr.outerHeight(),
					bodyPanel = grid.getBodyPanel(),
					bodyHeight = bodyPanel.height();
				// 判断是否在可视区域，若在可视区域，则判断提示显示的显示位置
				if (top > bodyHeight) {
					// 不在可视区域，则提示信息显示在下方，若是最后行则显示在上方
					// parseInt(ctr.parent().css('top')相对dataBody的高度
					if (parseInt(ctr.parent().css('top')) + height > grid.getDataBody().height()) {
				    	height = -error.css({top : height, left : 0}).outerHeight();
					}
				} else {
					var tempHeigth = ctr.parent().outerHeight() + error.outerHeight();
					if (tempHeigth > bodyHeight - 3) {
						//修复igrid不设置高度时，一行数据时错误label高度不够的问题。
						bodyPanel.css("min-height",tempHeigth + top);
						
						!bodyPanel.data("isFixed") && bodyPanel.data("isFixed", true).css("min-height", tempHeigth + top);
					} else {
						// 判断提示显示的显示位置
						if (top > 24 && (top + height > bodyHeight - 10)) {
							height = -error.css({top : height, left : 0}).outerHeight();
						}
					}
				}
				// 设置错误标签显示的位置
				error.css({
				            top : height,
				            left : 0
				        });
            }
        },
        /**
         * @description 列宽改变之后的修正活动编辑器位置
         * @param {Object}
         *            grid IGrid对象
         */
        fixActive : function(grid) {
            // 获取动态编辑器
            var activeEditors = grid.getActiveEditor(), rowEdit = grid.op.rowEdit, tempActiveEditor;
            if (activeEditors) {
                // 遍历所有的动态编辑器，并修正位置
                $.each(activeEditors, function(i, editCell) {
                    var ctr = editCell.children('.grid-editor'), td = ctr.data('caller');
                    if (td && td.width() > 10) {
                        GridEditor.fixPosition(grid, ctr, td, editCell);
                        //修复开启编辑行按TAB 一直停留在第一个
                        if (rowEdit && !tempActiveEditor && ctr.is(":focus")) {
                        	tempActiveEditor = ctr;
                        }
                    } else {
                        editCell.css("height", "").hide();
                    }
                });
                tempActiveEditor && tempActiveEditor.focus();
            }
        },
        /**
         * @description 验证数据
         * @param {Object}
         *            grid IGrid对象
         * @return {Boolean}
         */
        checkData : function(grid, allowEmpty) { 
            var op = grid.op;
            if (op.validOp && !$.isEmptyObject(op.validOp.rule)) {
                var records = grid.getRecords();
                if (records) {
                    // 验证新增数据
                    if (!grid.validRecords(records.insertedRecords, allowEmpty)) {
                        return false;
                    }
                    // 验证修改数据
                    if (op.isValidUpdate) {
                        if (!grid.validRecords(records.updatedRecords, true)) {
                            return false;
                        }
                    }
                    return records;
                }
            }
            return true;
        },
        /**
         * @description 请求数据编辑器
         * @param {Object}
         *            grid IGrid对象
         * @param {Object}
         *            col 列的配置信息
         * @param {Object}
         *            data 数据对象
         * @param {Number}
         *            index 行索引
         * @return {Boolean}
         */
        callDataEditor : function(grid, col, data, index) {
            // 获取单元格对象
            var tr = grid.getRow(index),
                td = grid.getRowCell(index, col._i);
            // 设置焦点定位行
            grid.setFocusRow(tr);
            // 显示编辑器
            this.showEditor(td, grid, true, col);
            // 验证编辑器
            col._editCtr.valid();
            
        },
		/** @description 添加或清除错误信息
		 * 
		 */
		updateErrorMsg: function (grid, record, field, errorMsg, isClear) {
			var gridOp = grid.op, errorMsgs, errorNo, tempErrorMsg;
			if (isClear) {
				tempErrorMsg = gridOp._errorMsg && gridOp._errorMsg[record._errorNo];
				if (tempErrorMsg && tempErrorMsg[field]) {
					tempErrorMsg[field] = null;
					tempErrorMsg.length--;
					// 若全部错误都清除，则将这行错误信息清除，并清除数据的错误号
					if (!tempErrorMsg.lenght) {
						gridOp._errorMsg[record._errorNo] = null;
						record._errorNo = null;
					}
				}
			} else {
				errorMsgs = gridOp._errorMsg ? gridOp._errorMsg : (gridOp._errorMsg = {});
				errorNo = record._errorNo ? record._errorNo : (record._errorNo = $.newGuid());
				tempErrorMsg = errorMsgs[errorNo] ? errorMsgs[errorNo] : (errorMsgs[errorNo] = {});
				tempErrorMsg[field] || (tempErrorMsg[field] = errorMsg);
				if (tempErrorMsg.length) {
					tempErrorMsg.length++;
				} else {
					tempErrorMsg.length = 1;
				}
			}
		}
    }
    /** 注册编辑器插件 */
    Ccay.UI.XControl.addPlugin("XGrid", "editor", {
            build : function(grid, op) {
                if (op.editMode) {
                    // 初始化活动编辑器
                    op._activeEditor = {};
                    // 初始化验证规则
                    op.validOp = {rule: {}};
                    // 创建编辑面板
                    if(!op.modalOp || !op.modalOp.fields){
                        op.modalOp = {
                            autoAlias : true,
                            modalName : "modal",
                            fields : [],
                            layoutTmpl : ""
                        };
                    }
                    var handler = op.handler;
                    // 添加列设置
                    handler.setColumn.add(GridEditor.setCol);
                    // 添加编辑事件
                    handler.click.add("edit", GridEditor.callEditor);
                    // 添加初始化验证
                    handler.initComplete.add(GridEditor.buildPanel);
                    handler.initComplete.add(GridEditor.initValid);
                    // 绑定数据后清除活动编辑器
                    handler.afterBindData.add(function(grid, op) {
                                grid.clearActiveEditor();
                            });
                    // 改变列宽时，修正编辑器的位置
                    handler.widthChange.add(GridEditor.fixActive);
                    // 横向滚动时，修正编辑器位置
                    handler.scrollX.add(function(grid) {
                                setTimeout(function() {
                                            GridEditor.fixActive(grid);
                                        }, 320);
                            });
                }
            }
        });

})(Ccay.UI.IGrid, Ccay.UI.IGrid.Const);
/**
 * igrid mvc化编辑使用
 */
Ccay.ViewLayout.add("gridedit",{layout :'<div class="ccay-igrid-editcell"> ${item} </div>'});
